package operations

import (
	"encoding/json"
	"fmt"
	"github.com/sirupsen/logrus"
	"io"
	"mydocker/common"
	"mydocker/container"
	"os"
	"os/exec"
	"path"
	"strings"
	// 需要导入 nsenter 包，以触发 C 代码
	_ "mydocker/nsenter"
)

// ExecContainer 重新进入容器
// 通过设置环境变量的方法，让写的程序真正执行
// 通过 setns 的系统调用，重新进入到指定的 PID 的 namespace 中
func ExecContainer(containerID string, cmdArray []string) {
	pid, err := getPidByContainerID(containerID)
	if err != nil {
		logrus.Errorf("Exec container getContainerPidByName %s error %v", containerID, err)
		return
	}
	cmd := exec.Command("/proc/self/exe", "exec")
	cmd.Stdin = os.Stdin
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	// 把命令拼接成字符串，便于传递
	cmdStr := strings.Join(cmdArray, " ")
	logrus.Infof("container pid: %s command: %s", pid, cmdStr)
	err = os.Setenv(common.EnvExecPid, pid)
	err = os.Setenv(common.EnvExecCmd, cmdStr)

	// 把指定 PID 进程的环境变量传递给新启动的进程，实现通过 exec 命令也能查询到容器的环境变量
	// 读取指定 PID 进程的环境变量
	containerEnvs := getEnvsByPid(pid)
	cmd.Env = append(os.Environ(), containerEnvs...)

	if err = cmd.Run(); err != nil {
		logrus.Errorf("Exec container %s error %v", containerID, err)
	}
}

func getPidByContainerID(containerID string) (string, error) {
	// 拼接出记录容器信息的文件路径
	dirPath := path.Join(common.DefaultContainerInfoPath, containerID)
	configFilePath := path.Join(dirPath, common.ConfigName)
	// 读取内容并解析
	contentBytes, err := os.ReadFile(configFilePath)
	if err != nil {
		return "", err
	}
	containerInfo := new(container.ContainerInfo)
	if err = json.Unmarshal(contentBytes, containerInfo); err != nil {
		return "", err
	}
	return containerInfo.Pid, nil
}

// getEnvsByPid 读取指定 PID 进程的环境变量
func getEnvsByPid(pid string) []string {
	envFilePath := fmt.Sprintf("/proc/%s/environ", pid)
	file, err := os.Open(envFilePath)
	if err != nil {
		logrus.Errorf("open env file, path: %s, err : %v", envFilePath, err)
		return nil
	}
	content, err := io.ReadAll(file)
	if err != nil {
		logrus.Errorf("read env file, path: %s, err : %v", envFilePath, err)
		return nil
	}
	return strings.Split(string(content), "\u0000")
}
